Skip to content

feat(sftp): DDS integration into the rover (DHEI-20905) - #445

Open
valenok4000 wants to merge 35 commits into
mainfrom
feat/ar-dds-integration-dhei-20905
Open

feat(sftp): DDS integration into the rover (DHEI-20905)#445
valenok4000 wants to merge 35 commits into
mainfrom
feat/ar-dds-integration-dhei-20905

Conversation

@valenok4000

Copy link
Copy Markdown

Make possible the DDS configuration from the Rover.

Copilot AI review requested due to automatic review settings June 29, 2026 12:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Rover-facing OpenAPI contract to support configuring a DDS-based file-transfer backend (file exposures/subscriptions), regenerates the Go API types from the updated spec, and introduces a feature flag to keep the file domain disabled until the downstream domains are available.

Changes:

  • Added FileExposure, FileSubscription, and PublicKey schemas to the OpenAPI spec and wired them into the Exposure/Subscription discriminator unions.
  • Regenerated oapi-codegen Go types to include the new file exposure/subscription variants and union helper methods.
  • Added a new FeatureFile feature flag (default disabled) to gate upcoming file/DDS domain functionality.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
rover-server/internal/api/server.gen.go Regenerated OpenAPI Go models/unions to include file exposure/subscription variants.
rover-server/api/openapi.yaml Adds file exposure/subscription schemas and updates discriminator mappings for request unions.
common/pkg/config/feature.go Adds a new FeatureFile flag (disabled by default) for the file/DDS domain rollout.
Files not reviewed (1)
  • rover-server/internal/api/server.gen.go: Generated file
Comments suppressed due to low confidence (1)

rover-server/internal/api/server.gen.go:4

  • The generated server stub no longer contains the SPDX license header. This can break REUSE/SPDX compliance checks for code files; if this file is intentionally generated, the generator/template should still emit the header (or the repo should explicitly exclude this path).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1776 to +1787
Exposure:
type: object
discriminator:
propertyName: type
mapping:
api: '#/components/schemas/ApiExposure'
event: '#/components/schemas/EventExposure'
file: '#/components/schemas/FileExposure'
oneOf:
- $ref: '#/components/schemas/ApiExposure'
- $ref: '#/components/schemas/EventExposure'
- $ref: '#/components/schemas/FileExposure'
Comment on lines 2468 to +2479
Subscription:
type: object
discriminator:
propertyName: type
mapping:
api: '#/components/schemas/ApiSubscription'
event: '#/components/schemas/EventSubscription'
file: '#/components/schemas/FileSubscription'
oneOf:
- $ref: '#/components/schemas/ApiSubscription'
- $ref: '#/components/schemas/EventSubscription'
- $ref: '#/components/schemas/FileSubscription'

@ron96g ron96g left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this is not done yet but here is a first review of the current code.

Comment thread file/api/v1/fileexposure_types.go Outdated
type FileExposureSpec struct {
// Approval configures how subscriptions to this file type are approved.
// +kubebuilder:default=Simple
Approval ApprovalStrategy `json:"approval,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be inside of an Object with strategy: ApprovalStrategy and TrustedTeams: []string, see API and Event

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Comment thread file/api/v1/fileexposure_types.go Outdated
// FileTypeRef references the file-domain FileType this exposure belongs to.
// It must live in the same namespace as this FileExposure.
// +kubebuilder:validation:Required
FileTypeRef ctypes.ObjectRef `json:"fileTypeRef"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ref on this layer is done via the string-value of fileType and not via ObjectRef. This is needed as we might need to switch the active FileType (if migrated)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment thread file/api/v1/fileexposure_types.go Outdated
// ZoneServiceConfigRef references the zone-scoped service configuration
// (provided by the SFTP/DDS domain) used to reach the backend for this exposure.
// +optional
ZoneServiceConfigRef *ctypes.ObjectRef `json:"zoneServiceConfigRef,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On this Layer we just pass the Zone-Ref and the domain itself must resolve it to its config, so Zone ctypes.ObjectRef

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread file/api/v1/filesubscription_types.go Outdated
type FileSubscriptionSpec struct {
// FileTypeRef references the file-domain FileType this subscription belongs to.
// +kubebuilder:validation:Required
FileTypeRef ctypes.ObjectRef `json:"fileTypeRef"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for the Exposure. Ref via string-value and not via Ref

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment thread file/api/v1/filesubscription_types.go Outdated
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`

// Active indicates whether this subscription has been provisioned.
Active bool `json:"active,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Active flag is only for Exposure and Type, not subscription. There we use conditions

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted

// file domain from a rover-domain FileSpecification (1:1) and is the canonical
// resource that FileExposure (1:1) and FileSubscription (1:n) reference via their
// fileTypeRef (mirrors event.EventType).
type FileTypeSpec struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FileType string is missing (similiar to eventType and basePath). Do we also need to add a specification field with the file-manager ref?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add Type as it's done for event. add specification

Comment thread file/api/v1/filetype_types.go Outdated

// ExposureRef references the file-domain FileExposure created for this file type (1:1).
// +optional
ExposureRef *ctypes.ObjectRef `json:"exposureRef,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both ExposureRef and SubscriptionRefs break our pattern and hierarchy: Type > Exposure > Subscription.
The FileType does not know about its Exposure and Subscription

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true. deleted

Comment thread file/api/v1/filetype_types.go Outdated
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`

// Active indicates whether this FileType has been provisioned.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is a bit misleading. This active-flag is used to indicate that THIS CR is the active one (singleton)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

type: array
items:
$ref: '#/components/schemas/EventScope'
FileExposure:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is aligned with the current Openapi-Spec?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbd

Comment thread rover/cmd/main.go Outdated
add / change file/rover api
add feature config, handler controller  wh for file
FileSpecification in progress
@valenok4000 valenok4000 changed the title DDS integration into the rover (DHEI-20905) feat(sftp): DDS integration into the rover (DHEI-20905) Jul 7, 2026

@ron96g ron96g left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments. The whole handler-logic in the file domain is still missing, correct?

Comment thread file/api/v1/fileexposure_types.go Outdated
// PublicKeys are the SSH public keys registered for the provider's SFTP user.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
PublicKeys []PublicKey `json:"publicKeys"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a root-level field? Did we not say that we want sub-objects like

sftp:
  publicKeys: []PublicKey
cloudwalker: 
  some: stuff 

**Cloudwalker is just a placeholder here :D

@valenok4000 valenok4000 Jul 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spec:
  approval: SIMPLE
  fileType: ...
  sftp:
    publicKeys:
      - key: ssh-rsa AAAAB3NzaC1...
        label: coran-int-dds
  visibility: ENTERPRISE
  zone:
    name: ...
    namespace: ...

// PublicKeys are the SSH public keys registered for the consumer's SFTP user.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
PublicKeys []PublicKey `json:"publicKeys"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as Exposure

@valenok4000 valenok4000 Jul 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adjusted to the structure (from design)

spec:
  sftp:
    clientId: <subscription application....>
    publicKeys:
       - key: ssh-rsa AAAAB3NzaC1...
         label: coran-int-dds
       - key: ssh-rsa AAAAB3NzaC1...
         label: coran-int-dds-2


out.Event = mapEventExposure(eventExp)

case "file":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there not "out" mapping for this? What about applicationinfo?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add out mapping.
applicationInfo???

Comment thread rover/api/v1/roadmap_types_test.go Outdated
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted (revert to initial state, it was (over)generated by AI

Comment thread rover/api/v1/rover_types.go Outdated
// It will be called by the file-domain handler
// (rover/internal/handler/rover/file, added in DHEI-20903) when logging/serialising
// the selected variant while creating the file-domain CRD.
func (v FileVariant) String() string {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need this. We no longer support multiple variants

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's good, will delete it


fileSubscription.Spec = filev1.FileSubscriptionSpec{
FileType: sub.FileType,
PublicKeys: mapPublicKeys(sub.PublicKeys),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add zone here as well just to keep it similiar. Even though it not used right now, correct?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think you will need the Requestor values for the Approval-Handling

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add zone here as well just to keep it similiar. Even though it not used right now, correct?

Refering to the internal documentation and design https://gitlab.devops.telekom.de/dhei/products/controlplane/docs/dds-file-integration
we don't have this zone for specification.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add zone here as well just to keep it similiar. Even though it not used right now, correct?

We keep it like this in design, not sure that similarity must be our point of truth.. will see

// MakeName generates a deterministic resource name for a file exposure or
// subscription: "<fileType>--<owner>" (spec_dcp naming), normalized.
func MakeName(fileType, ownerName string) string {
return filev1.MakeFileTypeName(fileType) + "--" + ownerName

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are functions to Normalize these values, see labelutil

// The file type identifier lives in metadata.name (no spec.type field in the
// internal CRD, per spec_dcp); the client-side name==type rule is enforced by
// rover-server / roverctl.
if st := filespecification.Spec.StorageType; st != "" && st != roverv1.FileStorageTypeSFTP {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed as done via CEL. Also I would remove it as not needed for now. We only have sftp and no plans to add more


// +kubebuilder:webhook:path=/validate-rover-cp-ei-telekom-de-v1-filespecification,mutating=false,failurePolicy=fail,sideEffects=None,groups=rover.cp.ei.telekom.de,resources=filespecifications,verbs=create;update,versions=v1,name=vfilespecification-v1.kb.io,admissionReviewVersions=v1

type FileSpecificationCustomValidator struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the entire webhook is not needed

exposesFiles := slices.ContainsFunc(rover.Spec.Exposures, func(exp roverv1.Exposure) bool {
return exp.Type() == roverv1.TypeFile
})
if (subscribesToFiles || exposesFiles) && !roverv1.IsFileTypeZoneSupported(rover.Spec.Zone) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As other comments states. Should be done via feature-flag logic in admin and not hardcoded in rover.

… and fix the rover mapper out

remove zone_supported flag and webhook as it's covered by featureEnabled flag
add rbac for file domain
…struct" lib as it was added by AI

add crypto lib and ssh pub key validation
move func desc to the original func
# Conflicts:
#	common/pkg/config/feature.go
#	rover-ctl/pkg/handlers/v0/rover.go
#	rover-ctl/pkg/handlers/v0/rover_test.go
#	rover-server/api/openapi.yaml
#	rover-server/internal/api/server.gen.go
#	rover-server/internal/mapper/rover/in/__snapshots__/exposure_test.snap
#	rover-server/internal/mapper/rover/in/__snapshots__/rover_test.snap
#	rover-server/internal/mapper/rover/in/__snapshots__/subscription_test.snap
#	rover-server/internal/mapper/rover/in/exposure.go
#	rover-server/internal/mapper/rover/in/subscription.go
#	rover-server/internal/mapper/rover/out/exposure.go
#	rover/api/v1/rover_types.go
#	rover/api/v1/zz_generated.deepcopy.go
#	rover/cmd/main.go
#	rover/config/crd/bases/rover.cp.ei.telekom.de_rovers.yaml
#	rover/config/rbac/role.yaml
#	rover/go.mod
#	rover/internal/controller/rover_controller.go
#	rover/internal/handler/rover/application/application.go
#	rover/internal/handler/rover/handler.go
#	rover/internal/webhook/v1/rover_webhook.go
# Conflicts:
#	rover-server/internal/mapper/rover/in/__snapshots__/exposure_test.snap
#	rover-server/internal/mapper/rover/in/__snapshots__/rover_test.snap
#	rover-server/internal/mapper/rover/in/__snapshots__/subscription_test.snap
#	rover-server/internal/mapper/rover/out/exposure.go
#	rover/api/v1/rover_types.go
#	rover/api/v1/zz_generated.deepcopy.go
#	rover/internal/handler/rover/handler.go
fix some issues
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants